/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.gui.frame; import icy.action.IcyAbstractAction; import icy.common.MenuCallback; import icy.gui.main.MainFrame; import icy.gui.util.ComponentUtil; import icy.main.Icy; import icy.resource.ResourceUtil; import icy.resource.icon.IcyIcon; import icy.system.thread.ThreadUtil; import icy.util.StringUtil; import java.awt.AWTEvent; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Image; import java.awt.LayoutManager; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ComponentListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.image.ImageObserver; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.util.ArrayList; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.WindowConstants; import javax.swing.border.Border; import javax.swing.event.EventListenerList; import javax.swing.event.InternalFrameEvent; import javax.swing.event.InternalFrameListener; /** * This class behave either as a JFrame or a JInternalFrame.<br> * IcyFrame should be 100% AWT safe * * @author Fabrice de Chaumont & Stephane Dallongeville */ public class IcyFrame implements InternalFrameListener, WindowListener, ImageObserver, PropertyChangeListener { private class SwitchStateAction extends IcyAbstractAction { /** * */ private static final long serialVersionUID = -4433831471426743128L; final IcyIcon detachIcon; final IcyIcon attachIcon; public SwitchStateAction() { super(""); detachIcon = new IcyIcon(ResourceUtil.ICON_WINDOW_EXPAND, 20); attachIcon = new IcyIcon(ResourceUtil.ICON_WINDOW_COLLAPSE, 20); setAccelerator(KeyEvent.VK_F3); refreshState(); } @Override public boolean doAction(ActionEvent e) { switchState(); return true; } void refreshState() { if (isInternalized()) { setName("Detach"); setIcon(detachIcon); setDescription("Externalize the window"); } else { setName("Attach"); setIcon(attachIcon); setDescription("Internalize the window"); } } } /** * list containing all active frames */ static ArrayList<IcyFrame> frames = new ArrayList<IcyFrame>(); /** * Return all active (not closed) IcyFrame */ public static ArrayList<IcyFrame> getAllFrames() { synchronized (frames) { return new ArrayList<IcyFrame>(frames); } } /** * Return all active IcyFrame which derive from the specified class */ public static ArrayList<IcyFrame> getAllFrames(Class<?> frameClass) { final ArrayList<IcyFrame> result = new ArrayList<IcyFrame>(); if (frameClass != null) { synchronized (frames) { for (IcyFrame frame : frames) if (frameClass.isInstance(frame)) result.add(frame); } } return result; } /** * Find IcyFrame corresponding to the specified JInternalFrame */ public static IcyFrame findIcyFrame(JInternalFrame frame) { synchronized (frames) { for (IcyFrame f : frames) if (f.getInternalFrame() == frame) return f; return null; } } public enum IcyFrameState { INTERNALIZED, EXTERNALIZED } protected IcyExternalFrame externalFrame; protected IcyInternalFrame internalFrame; /** * frame state (internal / external) */ protected IcyFrameState state; /** * sync flag for AWT thread process */ protected boolean syncProcess; /** * listeners */ protected EventListenerList frameEventListeners; /** * internals */ protected final MenuCallback defaultSystemMenuCallback; protected SwitchStateAction switchStateAction; protected boolean switchStateItemVisible; protected IcyFrameState previousState; public IcyFrame() { this("", false, true, false, false, true); } public IcyFrame(String title) { this(title, false, true, false, false, true); } public IcyFrame(String title, boolean resizable) { this(title, resizable, true, false, false, true); } public IcyFrame(String title, boolean resizable, boolean closable) { this(title, resizable, closable, false, false, true); } public IcyFrame(String title, boolean resizable, boolean closable, boolean maximizable) { this(title, resizable, closable, maximizable, false, true); } public IcyFrame(final String title, final boolean resizable, final boolean closable, final boolean maximizable, final boolean iconifiable) { this(title, resizable, closable, maximizable, iconifiable, true); } public IcyFrame(final String title, final boolean resizable, final boolean closable, final boolean maximizable, final boolean iconifiable, final boolean waitCreate) { super(); frameEventListeners = new EventListenerList(); defaultSystemMenuCallback = new MenuCallback() { @Override public JMenu getMenu() { return getDefaultSystemMenu(); } }; syncProcess = false; // set default state if (canBeInternalized()) state = IcyFrameState.INTERNALIZED; else state = IcyFrameState.EXTERNALIZED; switchStateItemVisible = true; // wanted default state previousState = IcyFrameState.INTERNALIZED; // create action after state has been set switchStateAction = new SwitchStateAction(); switchStateAction.setEnabled(canBeInternalized()); ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame = createExternalFrame(title); // redirect frame / window events externalFrame.addWindowListener(IcyFrame.this); externalFrame.setLocationRelativeTo(null); externalFrame.setResizable(resizable); externalFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // default size externalFrame.setSize(480, 400); internalFrame = createInternalFrame(title, resizable, closable, maximizable, iconifiable); // redirect frame / window events internalFrame.addInternalFrameListener(IcyFrame.this); // default size internalFrame.setSize(480, 400); // default system menu callback externalFrame.setSystemMenuCallback(defaultSystemMenuCallback); internalFrame.setSystemMenuCallback(defaultSystemMenuCallback); // register to the list synchronized (frames) { frames.add(IcyFrame.this); } } }, waitCreate); final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); // listen main frame mode change if (mainFrame != null) mainFrame.addPropertyChangeListener(MainFrame.PROPERTY_DETACHEDMODE, this); } /** * Permit IcyExternalFrame overriding */ protected IcyExternalFrame createExternalFrame(String title) { return new IcyExternalFrame(title); } /** * Permit IcyInternalFrame overriding */ protected IcyInternalFrame createInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable) { return new IcyInternalFrame(title, resizable, closable, maximizable, iconifiable); } /** * Return true if the frame can be internalized */ protected boolean canBeInternalized() { final MainFrame frame = Icy.getMainInterface().getMainFrame(); // internalization possible only in single window mode if (frame != null) return !frame.isDetachedMode(); return false; } /** * Refresh system menu */ public void updateSystemMenu() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.updateSystemMenu(); else externalFrame.updateSystemMenu(); } }, syncProcess); } /** * Close frame (send closing event) */ public void close() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.close(true); externalFrame.close(); } }, syncProcess); } /** * Dispose frame (send closed event) */ public void dispose() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.dispose(); else externalFrame.dispose(); } }, syncProcess); } /** go from detached to attached and opposite */ public void switchState() { if (isInternalized()) detach(); else attach(); } /** set the frame to be an inner frame on the desktop pane */ public void internalize() { if (isExternalized()) attach(); } /** the frame becomes detached in an independent frame */ public void externalize() { if (isInternalized()) detach(); } /** Set the frame to be an inner frame on the desktop pane */ public void attach() { if (isInternalized() || !canBeInternalized()) return; // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { // save current visible state final boolean visible = externalFrame.isVisible(); // hide external frame if (visible) externalFrame.setVisible(false); final JMenuBar menuBar = externalFrame.getJMenuBar(); final Container content = externalFrame.getContentPane(); // remove components from external frame externalFrame.setJMenuBar(null); externalFrame.setContentPane(new JPanel()); externalFrame.validate(); internalFrame.setJMenuBar(menuBar); internalFrame.setContentPane(content); internalFrame.validate(); // show internal frame if (visible) { internalFrame.setVisible(true); try { internalFrame.setSelected(true); } catch (PropertyVetoException e) { // ignore } } state = IcyFrameState.INTERNALIZED; // notify state change stateChanged(); } }, syncProcess); } /** Set the frame to be detached in an independent frame */ public void detach() { if (isExternalized()) return; // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { // save current visible state final boolean visible = internalFrame.isVisible(); // hide internal frame if (visible) internalFrame.setVisible(false); final JMenuBar menuBar = internalFrame.getJMenuBar(); final Container content = internalFrame.getContentPane(); // remove components from internal frame internalFrame.setJMenuBar(null); internalFrame.setContentPane(new JPanel()); internalFrame.validate(); externalFrame.setJMenuBar(menuBar); externalFrame.setContentPane(content); externalFrame.validate(); // show external frame if (visible) { externalFrame.setVisible(true); externalFrame.requestFocus(); } // TODO : we have to force a refresh with resizing or we get a refresh bug on // scrollbar (OSX only ?) // externalFrame.setSize(externalFrame.getWidth(), externalFrame.getHeight() - 1); // externalFrame.setSize(externalFrame.getWidth(), externalFrame.getHeight() + 1); state = IcyFrameState.EXTERNALIZED; // notify state change stateChanged(); } }, syncProcess); } /** * Called on state (internalized / externalized) change */ public void stateChanged() { // refresh switch action state switchStateAction.refreshState(); // refresh system menu updateSystemMenu(); // fire event if (isInternalized()) fireFrameInternalized(new IcyFrameEvent(IcyFrame.this, null, null)); else fireFrameExternalized(new IcyFrameEvent(IcyFrame.this, null, null)); } /** Center frame on the desktop */ public void center() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) ComponentUtil.center(internalFrame); else ComponentUtil.center(externalFrame); } }, syncProcess); } /** * Add to the container c */ public void addTo(final Container c) { if (isInternalized()) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { c.add(internalFrame); } }, syncProcess); } } /** * Add to the container c */ public void addTo(final Container c, final int index) { if (isInternalized()) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { c.add(internalFrame, index); } }, syncProcess); } } /** * @deprecated Use {@link #addToDesktopPane()} instead. */ @Deprecated public void addTo(final Container c, final Object constraints) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { c.add(internalFrame, constraints); } }, syncProcess); } /** * Add the frame to the Icy desktop pane with specified constraint. */ public void addToDesktopPane(final Object constraints) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { final JDesktopPane desktop = Icy.getMainInterface().getDesktopPane(); if (desktop != null) desktop.add(internalFrame, constraints); } }, syncProcess); } /** * Add the frame to the Icy desktop pane */ public void addToDesktopPane() { addToDesktopPane(JLayeredPane.DEFAULT_LAYER); } /** * @deprecated Use {@link #addToDesktopPane()} instead. */ @Deprecated public void addToMainDesktopPane() { addToDesktopPane(); } /** * Implement add method */ public void add(final Component comp) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.add(comp); else externalFrame.add(comp); } }, syncProcess); } /** * Implement add method */ public void add(final Component comp, final Object constraints) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.add(comp, constraints); else externalFrame.add(comp, constraints); } }, syncProcess); } /** * Implement add method */ public void add(final String name, final Component comp) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.add(name, comp); else externalFrame.add(name, comp); } }, syncProcess); } /** * Remove from the container */ public void removeFrom(final Container c) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { c.remove(internalFrame); } }, syncProcess); } /** * Implement removeAll method */ public void removeAll() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.removeAll(); else externalFrame.removeAll(); } }, syncProcess); } /** * Implement remove method */ public void remove(final Component comp) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.remove(comp); else externalFrame.remove(comp); } }, syncProcess); } /** * Remove the frame from the main pane of ICY */ public void removeFromMainDesktopPane() { removeFrom(Icy.getMainInterface().getDesktopPane()); } /** * Implement toFront method */ public void toFront() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.toFront(); else externalFrame.toFront(); } }, syncProcess); } /** * Implement toBack method */ public void toBack() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.toBack(); else externalFrame.toBack(); } }, syncProcess); } /** * Implement pack method */ public void pack() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.pack(); else externalFrame.pack(); } }, syncProcess); } public Container getFrame() { if (isInternalized()) return internalFrame; return externalFrame; } public IcyInternalFrame getIcyInternalFrame() { return internalFrame; } public IcyExternalFrame getIcyExternalFrame() { return externalFrame; } public JInternalFrame getInternalFrame() { return internalFrame; } public JFrame getExternalFrame() { return externalFrame; } /** * Indicate if system menu show display item to switch frame state (internal / external) */ public void setSwitchStateItemVisible(boolean value) { if (switchStateItemVisible != value) { switchStateItemVisible = value; switchStateAction.setEnabled(value); updateSystemMenu(); } } /** * @return the systemMenuCallback */ public MenuCallback getSystemMenuCallback() { // always have same callback on each frame final MenuCallback result = internalFrame.getSystemMenuCallback(); // default callback ? this means we set it to null if (result == defaultSystemMenuCallback) return null; return result; } /** * Set the system menu callback (this allow modification of system menu) * * @param value * the systemMenuCallback to set */ public void setSystemMenuCallback(MenuCallback value) { if (value != null) { internalFrame.setSystemMenuCallback(value); externalFrame.setSystemMenuCallback(value); } else { internalFrame.setSystemMenuCallback(defaultSystemMenuCallback); externalFrame.setSystemMenuCallback(defaultSystemMenuCallback); } } /** * Return the default system menu */ public JMenu getDefaultSystemMenu() { final JMenu result; if (isInternalized()) result = internalFrame.getDefaultSystemMenu(); else result = externalFrame.getDefaultSystemMenu(); if (switchStateItemVisible) { result.insert(switchStateAction, 0); if (result.getMenuComponentCount() > 1) result.insertSeparator(1); } return result; } /** * Implement getParent */ public Container getParent() { if (isInternalized()) return internalFrame.getParent(); return externalFrame.getParent(); } /** * Implement getContentPane method */ public Container getContentPane() { if (isInternalized()) return internalFrame.getContentPane(); return externalFrame.getContentPane(); } /** * Implement getRootPane method */ public JRootPane getRootPane() { if (isInternalized()) return internalFrame.getRootPane(); return externalFrame.getRootPane(); } /** * @return the switchStateAction */ public SwitchStateAction getSwitchStateAction() { return switchStateAction; } /** * Implement getMinimumSize method */ public Dimension getMinimumSize() { if (isInternalized()) return internalFrame.getMinimumSize(); return externalFrame.getMinimumSize(); } /** * Implement getMinimumSize method for internal frame only */ public Dimension getMinimumSizeInternal() { return internalFrame.getMinimumSize(); } /** * Implement getMinimumSize method for external frame only */ public Dimension getMinimumSizeExternal() { return externalFrame.getMinimumSize(); } /** * Implement getMaximumSize method */ public Dimension getMaximumSize() { if (isInternalized()) return internalFrame.getMaximumSize(); return externalFrame.getMaximumSize(); } /** * Implement getMaximumSize method for internal frame only */ public Dimension getMaximumSizeInternal() { return internalFrame.getMaximumSize(); } /** * Implement getMaximumSize method for external frame only */ public Dimension getMaximumSizeExternal() { return externalFrame.getMaximumSize(); } /** * Implement getPreferredSize method */ public Dimension getPreferredSize() { if (isInternalized()) return internalFrame.getPreferredSize(); return externalFrame.getPreferredSize(); } /** * Implement getPreferredSize method for internal frame only */ public Dimension getPreferredSizeInternal() { return internalFrame.getPreferredSize(); } /** * Implement getPreferredSize method for external frame only */ public Dimension getPreferredSizeExternal() { return externalFrame.getPreferredSize(); } /** * Implement getSize method */ public Dimension getSize() { if (isInternalized()) return internalFrame.getSize(); return externalFrame.getSize(); } /** * Implement getSize method for internal frame only */ public Dimension getSizeInternal() { return internalFrame.getSize(); } /** * Implement getSize method for external frame only */ public Dimension getSizeExternal() { return externalFrame.getSize(); } /** * Implement getHeight method */ public int getHeight() { if (isInternalized()) return internalFrame.getHeight(); return externalFrame.getHeight(); } /** * Implement getHeight method for internal frame only */ public int getHeightInternal() { return internalFrame.getHeight(); } /** * Implement getHeight method for external frame only */ public int getHeightExternal() { return externalFrame.getHeight(); } /** * Implement getWidth method */ public int getWidth() { if (isInternalized()) return internalFrame.getWidth(); return externalFrame.getWidth(); } /** * Implement getWidth method for internal frame only */ public int getWidthInternal() { return internalFrame.getWidth(); } /** * Implement getWidth method for external frame only */ public int getWidthExternal() { return externalFrame.getWidth(); } /** * Implement getX method */ public int getX() { if (isInternalized()) return internalFrame.getX(); return externalFrame.getX(); } /** * Implement getX method for internal frame only */ public int getXInternal() { return internalFrame.getX(); } /** * Implement getX method for external frame only */ public int getXExternal() { return externalFrame.getX(); } /** * Implement getY method */ public int getY() { if (isInternalized()) return internalFrame.getY(); return externalFrame.getY(); } /** * Implement getY method for internal frame only */ public int getYInternal() { return internalFrame.getY(); } /** * Implement getY method for external frame only */ public int getYExternal() { return externalFrame.getY(); } /** * Implement getLocation method */ public Point getLocation() { if (isInternalized()) return internalFrame.getLocation(); return externalFrame.getLocation(); } /** * Implement getLocation method */ public Point getLocationInternal() { return internalFrame.getLocation(); } /** * Implement getLocation method for external frame only */ public Point getLocationExternal() { return externalFrame.getLocation(); } /** * Implement getBounds method */ public Rectangle getBounds() { if (isInternalized()) return internalFrame.getBounds(); return externalFrame.getBounds(); } /** * Implement getBounds method for internal frame only */ public Rectangle getBoundsInternal() { return internalFrame.getBounds(); } /** * Implement getBounds method for external frame only */ public Rectangle getBoundsExternal() { return externalFrame.getBounds(); } /** * Implement getBounds method for external frame only */ public Rectangle getVisibleRect() { if (isInternalized()) return internalFrame.getVisibleRect(); // not supported on external frame if (externalFrame.isVisible()) return externalFrame.getBounds(); return new Rectangle(); } /** * Implement getJMenuBar method */ public JMenuBar getJMenuBar() { if (isInternalized()) return internalFrame.getJMenuBar(); return externalFrame.getJMenuBar(); } /** * Returns the content pane InputMap */ public InputMap getInputMap(int condition) { if (isInternalized()) return ((JPanel) internalFrame.getContentPane()).getInputMap(condition); return ((JPanel) externalFrame.getContentPane()).getInputMap(condition); } /** * Returns the content pane InputMap */ public ActionMap getActionMap() { if (isInternalized()) return ((JPanel) internalFrame.getContentPane()).getActionMap(); return ((JPanel) externalFrame.getContentPane()).getActionMap(); } /** * Implement getToolkit method */ public Toolkit getToolkit() { if (isInternalized()) return internalFrame.getToolkit(); return externalFrame.getToolkit(); } /** * Implement setTitle method */ public String getTitle() { if (isInternalized()) return internalFrame.getTitle(); return externalFrame.getTitle(); } /** * Return true if title bar is visible */ public boolean getTitleBarVisible() { if (isInternalized()) return internalFrame.isTitleBarVisible(); return externalFrame.isTitleBarVisible(); } /** * @return the displaySwitchStateItem */ public boolean isSwitchStateItemVisible() { return switchStateItemVisible; } /** * Implement getMousePosition method */ public Point getMousePosition() { if (isInternalized()) return internalFrame.getMousePosition(); return externalFrame.getMousePosition(); } /** * Implement isMinimized method */ public boolean isMinimized() { if (isInternalized()) return internalFrame.isIcon(); return ComponentUtil.isMinimized(externalFrame); } /** * Implement isMinimized method for internal frame only */ public boolean isMinimizedInternal() { return internalFrame.isIcon(); } /** * Implement isMinimized method for external frame only */ public boolean isMinimizedExternal() { return ComponentUtil.isMinimized(externalFrame); } /** * Implement isMaximized method */ public boolean isMaximized() { if (isInternalized()) return internalFrame.isMaximum(); return ComponentUtil.isMaximized(externalFrame); } /** * Implement isMaximized method for internal frame only */ public boolean isMaximizedInternal() { return internalFrame.isMaximum(); } /** * Implement isMaximized method for external frame only */ public boolean isMaximizedExternal() { return ComponentUtil.isMaximized(externalFrame); } /** * Implement isVisible method */ public boolean isVisible() { if (isInternalized()) return internalFrame.isVisible(); return externalFrame.isVisible(); } /** * Implement isResizable method */ public boolean isResizable() { if (isInternalized()) return internalFrame.isResizable(); return externalFrame.isResizable(); } /** * Implement isClosable method */ public boolean isClosable() { if (isInternalized()) return internalFrame.isClosable(); // external frame is always closable return true; } /** * return true if frame is in internalized state */ public boolean isInternalized() { return (state == IcyFrameState.INTERNALIZED); } /** * return true if frame is in externalized state */ public boolean isExternalized() { return (state == IcyFrameState.EXTERNALIZED); } /** * return true if frame is active */ public boolean isActive() { if (isInternalized()) return internalFrame.isSelected(); return externalFrame.isActive(); } /** * Implement isAlwaysOnTop method (only for externalized frame) */ public boolean isAlwaysOnTop() { return externalFrame.isAlwaysOnTop(); } /** * Implement hasFocus method */ public boolean hasFocus() { if (isInternalized()) return internalFrame.hasFocus(); return externalFrame.hasFocus(); } /** * Implement setTitle method */ public void setTitle(final String title) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setTitle(title); externalFrame.setTitle(title); } }, syncProcess); } /** * Implement setToolTipText method (only for internalized frame) */ public void setToolTipText(final String text) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { // only internal frame support it internalFrame.setToolTipText(text); // externalFrame.setToolTipText(text); } }, syncProcess); } /** * Implement setBackground method */ public void setBackground(final Color value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setBackground(value); externalFrame.setBackground(value); } }, syncProcess); } /** * Implement setForeground method */ public void setForeground(final Color value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setForeground(value); externalFrame.setForeground(value); } }, syncProcess); } /** * Implement setResizable method */ public void setResizable(final boolean value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setResizable(value); externalFrame.setResizable(value); } }, syncProcess); } /** * Implement setLocation method */ public void setLocation(final Point p) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setLocation(p); else externalFrame.setLocation(p); } }, syncProcess); } /** * Implement setLocation method */ public void setLocation(final int x, final int y) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setLocation(x, y); else externalFrame.setLocation(x, y); } }, syncProcess); } /** * Implement setLocation method for internal frame only */ public void setLocationInternal(final Point p) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setLocation(p); } }, syncProcess); } /** * Implement setLocation method for internal frame only */ public void setLocationInternal(final int x, final int y) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setLocation(x, y); } }, syncProcess); } /** * Implement setLocation method for external frame only */ public void setLocationExternal(final Point p) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setLocation(p); } }, syncProcess); } /** * Implement setLocation method for external frame only */ public void setLocationExternal(final int x, final int y) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setLocation(x, y); } }, syncProcess); } /** * Implement setSize method */ public void setSize(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setSize(d); else externalFrame.setSize(d); } }, syncProcess); } /** * Implement setSize method */ public void setSize(final int width, final int height) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setSize(width, height); else externalFrame.setSize(width, height); } }, syncProcess); } /** * Implement setSize method for internal frame only */ public void setSizeInternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setSize(d); } }, syncProcess); } /** * Implement setSize method for internal frame only */ public void setSizeInternal(final int width, final int height) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setSize(width, height); } }, syncProcess); } /** * Implement setSize method for external frame only */ public void setSizeExternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setSize(d); } }, syncProcess); } /** * Implement setSize method for external frame only */ public void setSizeExternal(final int width, final int height) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setSize(width, height); } }, syncProcess); } /** * Implement setPreferredSize method */ public void setPreferredSize(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setPreferredSize(d); else externalFrame.setPreferredSize(d); } }, syncProcess); } /** * Implement setPreferredSize method for internal frame only */ public void setPreferredSizeInternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setPreferredSize(d); } }, syncProcess); } /** * Implement setPreferredSize method for external frame only */ public void setPreferredSizeExternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setPreferredSize(d); } }, syncProcess); } /** * Implement setMinimumSize method */ public void setMinimumSize(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setMinimumSize(d); else externalFrame.setMinimumSize(d); } }, syncProcess); } /** * Implement setMaximumSize method */ public void setMaximumSize(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setMaximumSize(d); else externalFrame.setMaximumSize(d); } }, syncProcess); } /** * Implement setMinimumSize method for internal frame only */ public void setMinimumSizeInternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setMinimumSize(d); } }, syncProcess); } /** * Implement setMaximumSize method for internal frame only */ public void setMaximumSizeInternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setMaximumSize(d); } }, syncProcess); } /** * Implement setMinimumSize method for external frame only */ public void setMinimumSizeExternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setMinimumSize(d); } }, syncProcess); } /** * Implement setMaximumSize method for external frame only */ public void setMaximumSizeExternal(final Dimension d) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setMaximumSize(d); } }, syncProcess); } /** * Implement setBounds method */ public void setBounds(final Rectangle r) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setBounds(r); else externalFrame.setBounds(r); } }, syncProcess); } /** * Implement setMaximisable method */ public void setMaximisable(final boolean value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { // only for internal frame internalFrame.setMaximizable(value); } }, syncProcess); } /** * Implement setMinimized method */ public void setMinimized(final boolean value) { // only relevant if state changed if (isMinimized() ^ value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setMinimized(value); else externalFrame.setMinimized(value); } }, syncProcess); } } /** * Implement setMinimized method for internal frame only */ public void setMinimizedInternal(final boolean value) { // only relevant if state changed if (internalFrame.isMinimized() ^ value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setMinimized(value); } }, syncProcess); } } /** * Implement setMinimized method for external frame only */ public void setMinimizedExternal(final boolean value) { // only relevant if state changed if (externalFrame.isMinimized() ^ value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setMinimized(value); } }, syncProcess); } } /** * Implement setMaximized method */ public void setMaximized(final boolean value) { // only relevant if state changed if (isMaximized() ^ value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setMaximized(value); else externalFrame.setMaximized(value); } }, syncProcess); } } /** * Implement setMaximized method for internal frame only */ public void setMaximizedInternal(final boolean value) { // only relevant if state changed if (internalFrame.isMaximized() ^ value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setMaximized(value); } }, syncProcess); } } /** * Implement setMaximized method for external frame only */ public void setMaximizedExternal(final boolean value) { // only relevant if state changed if (externalFrame.isMaximized() ^ value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setMaximized(value); } }, syncProcess); } } /** * Implement setClosable method */ public void setClosable(final boolean value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setClosable(value); } }, syncProcess); } /** * Implement setDefaultCloseOperation method * * @see JFrame#setDefaultCloseOperation(int) */ public void setDefaultCloseOperation(final int operation) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setDefaultCloseOperation(operation); externalFrame.setDefaultCloseOperation(operation); } }, syncProcess); } /** * Implement setFocusable method */ public void setFocusable(final boolean value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setFocusable(value); externalFrame.setFocusable(value); } }, syncProcess); } /** * Implement setVisible method */ public void setVisible(final boolean value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setVisible(value); else externalFrame.setVisible(value); } }, syncProcess); } /** * Implement setAlwaysOnTop method (only for externalized frame) */ public void setAlwaysOnTop(final boolean alwaysOnTop) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { externalFrame.setAlwaysOnTop(alwaysOnTop); } }, syncProcess); } /** * Implement setJMenuBar method */ public void setJMenuBar(final JMenuBar m) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setJMenuBar(m); else externalFrame.setJMenuBar(m); } }, syncProcess); } /** * Hide or show the title bar (frame should not be displayable when you set this property) */ public void setTitleBarVisible(final boolean value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setTitleBarVisible(value); externalFrame.setTitleBarVisible(value); } }, syncProcess); } /** * Implement setLayout method */ public void setLayout(final LayoutManager layout) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setLayout(layout); else externalFrame.setLayout(layout); } }, syncProcess); } /** * Implement setBorder method (only for internal frame) */ public void setBorder(final Border border) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.setBorder(border); } }, syncProcess); } /** * Implement setContentPane method */ public void setContentPane(final Container value) { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.setContentPane(value); else externalFrame.setContentPane(value); } }, syncProcess); } /** * @return the syncProcess */ public boolean isSyncProcess() { return syncProcess; } /** * By default IcyFrame does asych processing, you can force sync processing<br> * with this property * * @param syncProcess * the syncProcess to set */ public void setSyncProcess(boolean syncProcess) { this.syncProcess = syncProcess; } /** * Frame becomes the active/focused frame */ public void requestFocus() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) { try { internalFrame.setSelected(true); } catch (PropertyVetoException e) { // ignore } } else externalFrame.requestFocus(); } }, syncProcess); } /** * Implement validate */ public void validate() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.validate(); else externalFrame.validate(); } }, syncProcess); } /** * Implement revalidate */ public void revalidate() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.revalidate(); else { externalFrame.invalidate(); externalFrame.repaint(); } } }, syncProcess); } /** * Implement repaint */ public void repaint() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { if (isInternalized()) internalFrame.repaint(); else externalFrame.repaint(); } }, syncProcess); } /** * Implement updateUI */ public void updateUI() { // AWT safe ThreadUtil.invoke(new Runnable() { @Override public void run() { internalFrame.updateUI(); } }, syncProcess); } /** * Fire frame activated event */ private void fireFrameActivated(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameActivated(e); } /** * Fire frame deactivated event */ private void fireFrameDeactivated(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameDeactivated(e); } /** * Fire frame closing event */ private void fireFrameClosing(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameClosing(e); } /** * Fire frame closed event */ private void fireFrameClosed(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameClosed(e); } /** * Fire frame iconified event */ private void fireFrameIconified(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameIconified(e); } /** * Fire frame deiconified event */ private void fireFrameDeiconified(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameDeiconified(e); } /** * Fire frame opened event */ private void fireFrameOpened(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameOpened(e); } /** * Fire frame internalized event */ void fireFrameInternalized(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameInternalized(e); } /** * Fire frame externalized event */ void fireFrameExternalized(IcyFrameEvent e) { for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class)) l.icyFrameExternalized(e); } /** * Implement addFrameListener method */ public void addFrameListener(IcyFrameListener l) { frameEventListeners.add(IcyFrameListener.class, l); } /** * Implement removeFrameListener method */ public void removeFrameListener(IcyFrameListener l) { frameEventListeners.remove(IcyFrameListener.class, l); } /** * Implement addComponentListener method */ public void addComponentListener(ComponentListener l) { internalFrame.addComponentListener(l); externalFrame.addComponentListener(l); } /** * Implement removeComponentListener method */ public void removeComponentListener(ComponentListener l) { internalFrame.removeComponentListener(l); externalFrame.removeComponentListener(l); } /** * Implement addKeyListener method */ public void addKeyListener(KeyListener l) { internalFrame.addKeyListener(l); externalFrame.addKeyListener(l); } /** * Implement addKeyListener method */ public void removeKeyListener(KeyListener l) { internalFrame.removeKeyListener(l); externalFrame.removeKeyListener(l); } /** * internal close stuff */ public void frameClosed(AWTEvent e) { final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); // remove listener on main frame mode change if (mainFrame != null) mainFrame.removePropertyChangeListener(MainFrame.PROPERTY_DETACHEDMODE, this); // remove others listeners externalFrame.removeWindowListener(IcyFrame.this); internalFrame.removeInternalFrameListener(IcyFrame.this); if (e instanceof InternalFrameEvent) { fireFrameClosed(new IcyFrameEvent(this, (InternalFrameEvent) e, null)); // don't forget to close external frame externalFrame.dispose(); } else if (e instanceof WindowEvent) { fireFrameClosed(new IcyFrameEvent(this, null, (WindowEvent) e)); // don't forget to close internal frame internalFrame.dispose(); } // easy onClosed handling onClosed(); } /** * easy onClosed job */ public void onClosed() { // unregister from list synchronized (frames) { frames.remove(this); } // release some stuff else we have cycling reference externalFrame.systemMenuCallback = null; internalFrame.systemMenuCallback = null; switchStateAction = null; } @Override public void internalFrameActivated(InternalFrameEvent e) { fireFrameActivated(new IcyFrameEvent(this, e, null)); } @Override public void internalFrameClosed(InternalFrameEvent e) { frameClosed(e); } @Override public void internalFrameClosing(InternalFrameEvent e) { fireFrameClosing(new IcyFrameEvent(this, e, null)); } @Override public void internalFrameDeactivated(InternalFrameEvent e) { fireFrameDeactivated(new IcyFrameEvent(this, e, null)); } @Override public void internalFrameDeiconified(InternalFrameEvent e) { fireFrameDeiconified(new IcyFrameEvent(this, e, null)); } @Override public void internalFrameIconified(InternalFrameEvent e) { fireFrameIconified(new IcyFrameEvent(this, e, null)); } @Override public void internalFrameOpened(InternalFrameEvent e) { fireFrameOpened(new IcyFrameEvent(this, e, null)); } @Override public void windowActivated(WindowEvent e) { fireFrameActivated(new IcyFrameEvent(this, null, e)); } @Override public void windowClosed(WindowEvent e) { frameClosed(e); } @Override public void windowClosing(WindowEvent e) { fireFrameClosing(new IcyFrameEvent(this, null, e)); } @Override public void windowDeactivated(WindowEvent e) { fireFrameDeactivated(new IcyFrameEvent(this, null, e)); } @Override public void windowDeiconified(WindowEvent e) { fireFrameDeiconified(new IcyFrameEvent(this, null, e)); } @Override public void windowIconified(WindowEvent e) { fireFrameIconified(new IcyFrameEvent(this, null, e)); } @Override public void windowOpened(WindowEvent e) { fireFrameOpened(new IcyFrameEvent(this, null, e)); } @Override public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { if (isInternalized()) return internalFrame.imageUpdate(img, infoflags, x, y, width, height); return externalFrame.imageUpdate(img, infoflags, x, y, width, height); } @Override public void propertyChange(PropertyChangeEvent evt) { if (StringUtil.equals(evt.getPropertyName(), MainFrame.PROPERTY_DETACHEDMODE)) { // window mode has been changed final boolean detachedMode = ((Boolean) evt.getNewValue()).booleanValue(); // detached mode set --> externalize if (detachedMode) { // save previous state previousState = state; externalize(); // disable switch state item if (switchStateAction != null) switchStateAction.setEnabled(false); } else { // restore previous state if (previousState == IcyFrameState.INTERNALIZED) internalize(); // enable switch state item if (switchStateAction != null) switchStateAction.setEnabled(true); } } } }